/* 
 * File:   Model.cpp
 * Author: mvdr
 * 
 * Created on March 19, 2013, 3:01 PM
 */

#include "Model.h"
#include <algorithm>
#include <iostream>
#include <ctime>


using namespace std;

Model::Model() {
    buildStates();
    buildRelations();
}


Model::~Model() {
    for (int i = 0; i != 3; ++i)
    {
        for (int j = 0; j != d_states.size(); ++j)
            delete[] d_relations[i][j];
        delete[] d_relations[i];
    }
    
    delete[] d_relations;
}

void Model::buildStates() {    
    vector<char> allCards = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 
    vector<vector<char> > players (3, vector<char> (0));
    
    combine(players, allCards, 2, 0);
}

void Model::combine(vector<vector<char> > cur, vector<char> left, size_t length,
        int curP) {
    if (cur[curP].size() == length)
    {   
        if (curP != 2)
            switchPlayer(cur, length, curP + 1);
        else
        {
            State tempState;
            for (int p = 0; p != 3; ++p)
                tempState.setCards(p, cur[p][0], cur[p][1]);
            d_states.push_back(tempState);
        }
    }
    else 
    {
        for (size_t i = 0; i != left.size(); ++i)
        {
            vector<vector<char> > newCur (cur);            
            newCur[curP].push_back(left[i]);             
            combine(newCur, vector<char> (left.begin() + i + 1, left.end()),
                    length, curP);
        }
    }    
}

void Model::switchPlayer(vector<vector<char> > cur, size_t length, int curP) {
    vector<char> left;
    
    for (char i = 1; i != 10; ++i)
    {
        bool add = true;
        
        for (int p = 0; p != curP; ++p)
            for (size_t j = 0; j != cur[p].size(); ++j)
            {
                add = add & (cur[p][j] != i);
            }
        
        if (add)
            left.push_back(i);
    }
    
    combine(cur, left, length, curP);  
    
}

void Model::buildRelations() {
    
    long nStates = d_states.size();
    
    d_relations = new bool** [3];
    d_startRelations = new bool** [3];
    for (int i = 0; i != 3; ++i)
    {
        d_relations[i] = new bool * [nStates];
        d_startRelations[i] = new bool * [nStates];
        for (int j = 0; j != nStates; ++j)
        {
            d_relations[i][j] = new bool [nStates];
            d_startRelations[i][j] = new bool [nStates];
        }
            
    }
    
    float maxi = 3 * (nStates * nStates + nStates) / 2;
    long count = 0;

    
    for (int p = 0; p != 3; ++p)
    {   
        
        for (int s = 0; s != nStates; ++s)
        {            
            for (int t = 0 + s; t != nStates; ++t)
            {
                d_startRelations[p][s][t] = d_states[s].sameFor(d_states[t], p);
                d_startRelations[p][t][s] = d_startRelations[p][s][t];      
                
                if (++count % 5000 == 0)
                    cout << "Building relation matrices... " << 
                            int(100 * (count / maxi)) << "%\r";
                
            }
        }       
    }
    
    cout << "Building relation matrices... Done!           \n";
}

void Model::initRelations() {       
    for (size_t p = 0; p != 3; ++p)
        for (size_t s = 0; s != d_states.size(); ++s)
           for (size_t t = 0; t != d_states.size(); ++t)            
                d_relations[p][s][t] = d_startRelations[p][s][t];
}

void Model::cutOff(size_t idx, size_t player) {
    for (size_t s = 0; s != d_states.size(); ++s)
    {
        d_relations[player][s][idx] = false;
        d_relations[player][idx][s] = false;
    }
}

size_t Model::playerConsidersPossible(size_t p, size_t idx) const {
    size_t retval = 0;
    for (size_t s = 0; s != d_states.size(); ++s)
        if(d_relations[p][s][idx])
            ++retval;
    return retval;
}

bool Model::playerConsidersStatePossible(size_t p, size_t i, size_t j) const {
    return d_relations[p][i][j];
}

bool Model::playerKnowsState(size_t player, size_t idx) const {
    if (!d_relations[player][idx][idx])
        return false;
    
    for (size_t s = 0; s != d_states.size(); ++s)
        if ((s != idx) & d_relations[player][s][idx])
            return false;
    
    return true;        
}

size_t Model::knownStates(size_t p) const {
    size_t known = 0;
    
    for (size_t s = 0; s != d_states.size(); ++s)
        if (playerKnowsState(p, s))
            ++known;
    
    return known;
        
}

void Model::printPossibleStates(int p, int state) const {    
    cout << "Player " << p + 1 << " considers the following states possible:";
    size_t counter = 0;
    for (int i = 0; i != d_states.size(); ++i)
    {        
        if(d_relations[p][state][i])
        {
            if (counter++ % 3 == 0)
                cout << '\n';
            cout << d_states[i] << "; ";
        }
    }
    
    cout << "\b\b.\n\n";
}
